// 12.4.1 包扩展
// 变参模板（Variadic Templates）是C++11引入的一项重要特性，它允许模板接受任意数量的参数。包扩展（Pack Expansion）是变参模板的核心机制，用于操作和使用参数包。

// 变参模板的基本概念
// 变参模板使用省略号（...）语法声明参数包：
// 类模板的变参形式
template <typename... Types>
class Tuple
{
    // ...
};

// 函数模板的变参形式
template <typename... Args>
void printAll(Args... args)
{
    // ...
}
// 参数包可以包含任意数量的参数（包括零个），这大大增强了模板的灵活性。

// 包扩展的基本语法
// 包扩展是将参数包中的每个元素应用于某个模式（pattern），然后将结果组合起来的过程。基本语法是在包含参数包的模式后面添加省略号：
template <typename... Types>
class Tuple
{
    // ...
};

// 包扩展示例
template <typename... Types>
class NestedTuple
{
    Tuple<Types...> nested; // 包扩展：展开为Tuple<T1, T2, T3, ...>
};

// 包扩展的上下文
// 包扩展可以在多种上下文中使用：
// 1.模板参数列表：
template <typename... Types>
class Tuple
{
    // ...
};

template <typename... Types>
using AliasTuple = Tuple<Types...>;

// 2.函数参数列表：
template <typename... Args>
void forward(Args &&...args)
{
    someFunction(std::forward<Args>(args)...);
}

// 3.初始化列表：
template <typename... Types>
auto makeArray(Types &&...args)
{
    return std::array<std::common_type_t<Types...>, sizeof...(Types)>{
        std::forward<Types>(args)...};
}

// 4.基类列表：
template <typename... Mixins>
class Combined : public Mixins...
{
    using Mixins::Mixins...; // 继承所有构造函数
};

// 5.异常规范（C++17之前）：
template <typename... Exceptions>
void mayThrow() throw(Exceptions...);

// 6.Lambda捕获（C++14）：
template <typename... Args>
auto createLambda(Args... args)
{
    return [args...]() { /*...*/ };
}

// 包扩展的模式
// 包扩展可以应用于各种模式：
// 1.简单名称：
template <typename... Types>
void printTypes(Types... args)
{
    (std::cout << ... << args) << std::endl; // C++17折叠表达式
}

// 2.复杂表达式：
template <typename... Args>
void forward(Args &&...args)
{
    someFunction(std::forward<Args>(args)...); // 对每个参数应用std::forward
}

// 3.类型转换：
template <typename... Types>
void convertAll(Types... args)
{
    std::tuple<std::string...> strings = {std::to_string(args)...};
}

// 4.成员访问：
template <typename... Objects>
void callMethods(Objects... objs)
{
    (objs.method(), ...); // C++17折叠表达式
}

// 多重包扩展
// 一个表达式中可以包含多个参数包，它们会同步展开：
template <typename... Types, typename... Args>
void createObjects(Args &&...args)
{
    std::tuple<Types...> objects(std::forward<Args>(args)...);
    // 要求sizeof...(Types) == sizeof...(Args)
}

// 包扩展的顺序
// 包扩展的顺序是从左到右的，这在某些情况下很重要：
template <typename... Args>
void process(Args... args)
{
    int dummy[] = {(std::cout << args << std::endl, 0)...};
    // 按照args的顺序打印每个参数
}

// sizeof... 运算符
// sizeof... 运算符返回参数包中的元素数量：
template <typename... Args>
void countArgs(Args... args)
{
    std::cout << "Number of arguments: " << sizeof...(Args) << std::endl;
    // 或者
    std::cout << "Number of arguments: " << sizeof...(args) << std::endl;
}